
package com.wobaby.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

import javax.ejb.EJBException;

import com.wobaby.util.config.Config;
import com.wobaby.util.log.Log;
import com.wobaby.util.log.LogPrinter;

// Referenced classes of package com.wobaby.util:
//            RenditionUncheckedException, RenditionCheckedException

public class ExceptionSupport
{

    private ExceptionSupport()
    {
    }

    public static String getRootStackTrace(Throwable throwable)
    {
        Throwable root = findRootException(throwable);
        return getStackTrace(root);
    }

    public static String getStackTrace(Throwable throwable)
    {
        String trace;
        try
        {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            PrintStream ps;
            //if(!Localizer.isEnabled())
                ps = new PrintStream(outputStream);
            //else
                //ps = new PrintStream(outputStream, false, I18NHelper.getCharacterEncoding());
            throwable.printStackTrace(ps);
            outputStream.close();
            //if(!Localizer.isEnabled())
                trace = outputStream.toString();
            //else
              //  trace = outputStream.toString(I18NHelper.getCharacterEncoding());
        }
        catch(IOException ioe)
        {
            trace = "Couldn't get stack trace for: " + throwable;
        }
        return trace;
    }

    public static boolean displayStackTraceInformation(Throwable ex, String logName)
    {
        ArrayList list = extractPackageNamesFromConfig();
        if(list == null || list.size() < 1)
            return displayStackTraceInformation(ex, "com.wobaby", logName);
        Iterator i = list.iterator();
        String configNames[] = new String[list.size()];
        int index = 0;
        while(i.hasNext()) 
            configNames[index++] = (String)i.next();
        return displayStackTraceInformation(ex, configNames, logName);
    }

    public static boolean displayStackTraceInformation(Throwable ex, String searchPackages[], String logName)
    {
        if(!testThrowable(ex, logName))
            return false;
        if(searchPackages == null || searchPackages.length == 0)
            return false;
        boolean result = true;
        for(int i = 0; i < searchPackages.length; i++)
        {
            if(printStackTraceInformation(ex, searchPackages[i], logName));
            result = false;
        }

        return result;
    }

    public static boolean displayStackTraceInformation(Throwable ex, String searchPackage, String logName)
    {
        if(!testThrowable(ex, logName))
            return false;
        else
            return printStackTraceInformation(ex, searchPackage, logName);
    }

    public static Throwable findRootException(Throwable ex)
    {
        Throwable returnValue = ex;
        Throwable prevValue = returnValue;
        int count = 0;
        do
        {
            if(returnValue == null)
                break;
            count++;
            prevValue = returnValue;
            if(returnValue instanceof UndeclaredThrowableException)
            {
                returnValue = ((UndeclaredThrowableException)returnValue).getUndeclaredThrowable();
                continue;
            }
            if(returnValue instanceof InvocationTargetException)
            {
                returnValue = ((InvocationTargetException)returnValue).getTargetException();
                continue;
            }
            if(returnValue instanceof RemoteException)
            {
                returnValue = ((RemoteException)returnValue).getCause();
                continue;
            }
            if(returnValue instanceof EJBException)
            {
                returnValue = ((EJBException)returnValue).getCausedByException();
                continue;
            }
            if(returnValue instanceof ServerException)
            {
                returnValue = ((ServerException)returnValue).detail;
                continue;
            }
            if(returnValue instanceof RenditionUncheckedException)
            {
                returnValue = ((RenditionUncheckedException)returnValue).getException();
                continue;
            }
            if(!(returnValue instanceof RenditionCheckedException))
                break;
            returnValue = ((RenditionCheckedException)returnValue).getException();
        } while(count != 10);
        if(returnValue == null)
            returnValue = prevValue;
        return returnValue;
    }

    public static Throwable findRootExceptionSimple(Throwable t)
    {
        if(t.getCause() == null)
            return t;
        else
            return findRootExceptionSimple(t.getCause());
    }

    private static boolean testThrowable(Throwable ex, String logName)
    {
        if(null == ex)
        {
            Log.getLog(logName).warn(thisObj, "Null stack trace reference! ");
            return false;
        } else
        {
            StackTraceElement stackElements[] = ex.getStackTrace();
            Log.getLog(logName).debug(thisObj, "There are total " + stackElements.length + " element" + (stackElements.length != 1 ? "s" : "") + " of the stack trace\n");
            return true;
        }
    }

    protected static boolean printStackTraceInformation(Throwable ex, String searchPackage, String logName)
    {
        if(searchPackage == null || "".equals(searchPackage))
        {
            Log.getLog(logName).warn(thisObj, "Null package name reference! ");
            return false;
        }
        StackTraceElement stackElements[] = ex.getStackTrace();
        for(int lcv = 0; lcv < stackElements.length; lcv++)
        {
            String className = stackElements[lcv].getClassName();
            String packageName = extractPackageName(className);
            if(packageName.startsWith(searchPackage))
                Log.getLog(logName).debug(thisObj, "Element " + lcv + ": " + stackElements[lcv].toString());
        }

        return true;
    }

    public static String extractPackageName(String fullClassName)
    {
        if(null == fullClassName || "".equals(fullClassName))
            return "";
        int lastDot = fullClassName.lastIndexOf('.');
        if(0 >= lastDot)
            return "";
        else
            return fullClassName.substring(0, lastDot);
    }

    private static ArrayList extractPackageNamesFromConfig()
    {
        String allNames = Config.getConfig().get("stackTrace/packages", "SEARCH_PACKAGE_NAME");
        if(allNames == null || "".equals(allNames))
            return null;
        StringTokenizer st = new StringTokenizer(allNames, ",");
        int numTokens = st.countTokens();
        if(numTokens < 1)
            return null;
        ArrayList list = new ArrayList(numTokens);
        int count = 0;
        String nToken;
        for(; st.hasMoreTokens(); list.add(count++, nToken))
            nToken = st.nextToken();

        return list;
    }

    public static void logStackTrace(String logname, String message)
    {
        LogPrinter log = Log.getLog(logname);
        if(log.configuredFor(0))
        {
            Exception e = new Exception();
            e.fillInStackTrace();
            log.trace(com.wobaby.util.ExceptionSupport.class, message, e);
        }
    }

    public static String getMessage(Throwable ex)
    {
        String msg = ex.getClass().getName();
        int dot = msg.lastIndexOf(".");
        if(dot != -1)
            msg = msg.substring(dot + 1);
        if(ex.getMessage() != null)
            msg = msg + ": " + ex.getMessage();
        return msg;
    }

    public static String getRootMessage(Throwable throwable)
    {
        Throwable root = findRootException(throwable);
        return getMessage(root);
    }

    public static final String SEARCH_PACKAGE_NAME = "com.wobaby";
    public static final String DEFAULT_LOG_NAME = "renditionStackTrace";
    public static final String DELIMITER = ",";
    public static final ExceptionSupport thisObj = new ExceptionSupport();

}